﻿using Application.Common.Interfaces;
using FluentValidation;
using Microsoft.EntityFrameworkCore;
using System.Text.RegularExpressions;

namespace Application.Features.Roles.Commands.Update;

/// <summary>
/// 校验修改角色信息
/// </summary>
public class UpdateRoleCommandValidator : AbstractValidator<UpdateRoleCommand>
{
    private readonly IApplicationDbContext _context;
    public UpdateRoleCommandValidator(IApplicationDbContext context)
    {
        _context = context;
        RuleFor(v => v.RoleId)
            .MustAsync(RoleExistsAsync).WithMessage($"数据不存在！");

        RuleFor(v => v.RoleId)
           .MustAsync(AllowedUpdateRoleAsync).WithMessage($"禁止修改！");

        RuleFor(v => v.RoleName)
             .MaximumLength(20).WithMessage("超出最大长度20个字符")
             .MustAsync(BeUniqueRoleNameAsync).WithMessage($"角色名已存在");

        RuleFor(v => v.Description)
             .MaximumLength(50).WithMessage("超出最大长度50个字符");

        RuleFor(v => v.RoleCode)
             .MaximumLength(50).WithMessage("超出最大长度50个字符")
             .MustAsync(BeUniqueRoleCodeAsync).WithMessage($"角色标识已存在")
             .Must(BeValidAlphabetOnly).WithMessage($"角色标识只能是字母");
    }

    /// <summary>
    /// 检查数据是否存在
    /// </summary>
    /// <param name="command"></param>
    /// <param name="roleId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    private async Task<bool> RoleExistsAsync(UpdateRoleCommand command, long roleId, CancellationToken cancellationToken)
    {
        return await _context.Roles.AnyAsync(x => x.Id == roleId && x.ConcurrencyStamp == command.ConcurrencyStamp);
    }

    /// <summary>
    /// 校验角色名是否唯一
    /// </summary>
    /// <param name="command">请求参数</param>
    /// <param name="roleName"></param>
    /// <param name="cancellationToken">取消标记</param>
    /// <returns></returns>
    private async Task<bool> BeUniqueRoleNameAsync(UpdateRoleCommand command, string roleName, CancellationToken cancellationToken)
    {
        var role = await _context.Roles.FirstOrDefaultAsync(x => x.RoleName == roleName && x.ConcurrencyStamp == command.ConcurrencyStamp, cancellationToken);
        if (role == null || role.Id == command.RoleId)
        {
            return true;
        }
        return false;
    }

    /// <summary>
    /// 校验角色标识是否唯一
    /// </summary>
    ///  <param name="command">请求参数</param>
    /// <param name="roleCode">角色名称</param>
    /// <param name="cancellationToken">取消标记</param>
    /// <returns></returns>
    private async Task<bool> BeUniqueRoleCodeAsync(UpdateRoleCommand command, string roleCode, CancellationToken cancellationToken)
    {
        var role = await _context.Roles.FirstOrDefaultAsync(x => x.RoleCode == roleCode, cancellationToken);
        if (role == null || role.Id == command.RoleId)
        {
            return true;
        }

        return false;
    }

    /// <summary>
    /// 校验是否仅是字母
    /// </summary>
    /// <param name="roleCode">角色标识</param>
    /// <returns></returns>
    private bool BeValidAlphabetOnly(string roleCode)
    {
        return Regex.IsMatch(roleCode, "^[a-zA-Z]+$");
    }

    private async Task<bool> AllowedUpdateRoleAsync(long roleId, CancellationToken cancellationToken)
    {
        var existingRole = await _context.Roles.SingleOrDefaultAsync(x => x.Id == roleId);

        if (existingRole == null)
        {
            return false;
        }
        if (string.Equals(existingRole.RoleCode, "admin", StringComparison.OrdinalIgnoreCase))
        {
            return false;
        }
        return true;
    }
}